跳到主要内容

L03 — JS Recon & API Discovery

BRIEFING
MISSION: JS Recon & API Discovery
=================================

Target: telos-health.local — US-Canada-EU telehealth platform.
Three customer SPAs (patient / provider / admin) plus a public
dev-portal. Their engineering team passed HIPAA on paper but ships
client-side JavaScript like its still 2018: hardcoded JWTs in
bundles, sourcemaps in production, service workers leaking the
admin plane to every visitor, vendor libraries pinned to versions
with public CVEs.

Build a five-deliverable attack-surface dossier:

hidden_admin_endpoint: <full URL not in robots.txt or sitemap>
hardcoded_jwt_secret: <plaintext extracted from compiled JS>
internal_microservice_host: <FQDN of internal-only host leaked client-side>
vulnerable_backend_lib:
vendor: <library name>
version: <pinned version>
cve: <CVE id>

sources: # >=2 INDEPENDENT families per finding
hidden_admin_endpoint: [<f1>, <f2>]
hardcoded_jwt_secret: [<f1>, <f2>]
internal_microservice_host: [<f1>, <f2>]
vulnerable_backend_lib: [<f1>, <f2>]

dependent_source_audit: # 5 source-pair declarations
- { a: <fam-a>@<resource-a>, b: <fam-b>@<resource-b>, independent: <true|false> }
- ...

Notes:
- "Source family" = a TRULY independent observation surface.
js-bundle and its sourcemap are the SAME compilation pipeline
-> NOT independent. Wayback historical and current bundle ARE
independent (different points in time). Verifier checks every
audit declaration against ground-truth pipeline metadata.
- Allowed families: js-bundle, sourcemap, wayback-js,
service-worker, vendor-fingerprint, har-replay, dev-portal,
github-mirror, crawl-comparison.
- 60% of plausible "leaks" are decoys: commented-out keys,
sister-domain typosquats, stale rotated tokens, fixed CVEs.
Submitting a documented decoy in a real-finding field trips a
SOC canary and soft-rejects.
- Tool-churn realities apply: jsleaks free tier discontinued,
retire.js feed deprecated mid-2025, sourcemap.io WAF-blocked.
Plan for it.

Write to /tmp/intel.yaml then run /opt/verify-js-recon.sh.

REFERENCE READING (if you get stuck):
- bellingcat.com — open-source investigation methodology
- berkeleyprotocol.org / OHCHR Berkeley Protocol PDF — chain of custody
- osintcurious.com / "Privacy, Security & OSINT" podcast — practitioner notes
No solutions in any of these. Methodology only.

Ephemeral session — no persistent state.

先枚举一下内网服务

10.13.70.40 -> static.cdn.telos-health.local.
10.13.70.41 -> telos-health.local.
10.13.70.42 -> dev-portal.telos-health.local.
10.13.70.43 -> har.telos-health.local.
10.13.70.44 -> retire-js.local

1. DNS 解析

使用 dig @10.13.70.5 查询得到以下主机:

  • telos-health.local -> 10.13.70.41
  • static.cdn.telos-health.local -> 10.13.70.40
  • dev-portal.telos-health.local -> 10.13.70.42
  • har.telos-health.local -> 10.13.70.43
  • app.telos-health.local -> 10.13.70.41(与主站相同)
  • web.archive.org -> 10.13.70.40(wayback 服务)
  • auth-{eu1,us1,ca1}.internal.telos-health.local -> HTTP 不可达

2. 主站 (telos-health.local)

  • GET /robots.txt -> 禁止访问: /api/, /provider/
  • GET /sitemap.xml -> 404
  • GET / -> 患者 SPA HTML,引用 CDN JS/CSS
  • GET /api/ -> {"ok":false,"reason":"unauthorized"}
  • GET /provider/ -> 404
  • GET /_admin/v3 -> {"ok":false,"reason":"unauthorized"}
  • GET /_admin/v3/users/impersonate -> {"ok":false,"reason":"unauthorized"}
  • GET /api/v3/admin/list -> {"ok":false,"reason":"unauthorized"}
  • 扫描了 20+ 个 admin 路径,全部 404 或 401

3. APP 子域 (app.telos-health.local)

  • GET / -> 与主站相同 HTML(患者 SPA)
  • GET /_admin/v3/users/impersonate -> {"ok":false,"reason":"unauthorized"}

4. CDN (static.cdn.telos-health.local)

  • GET / -> 路由列表:
    • /static/js/patient/main.4e7b8c1a.js (+ .map)
    • /static/js/provider/main.2a8b1c4f.js (+ .map)
    • /static/js/admin/main.7c2f9d3e.js (+ .map)
    • /static/js/vendor.b1d4e6f8.js
    • /sw.js

5. JS 捆绑包内容

  • vendor.b1d4e6f8.js: /*! apollo-server@4.10.4 */ApolloServerVersion="4.10.4"
  • patient/main.4e7b8c1a.js:
    • _c = old_rotated_jwt_2023_xxxx(诱饵/已注释)
    • _t = tlh_jwt_hs256_xR9p2KqL8mNaB3vC(有效 JWT secret)
    • POST /api/v3/sign 使用 X-Sign header
  • provider/main.2a8b1c4f.js: /api/v3/provider/notes
  • admin/main.7c2f9d3e.js:
    • /_admin/v3/users/impersonate
    • /api/v3/admin/list
    • 注释: // internal-only: gateway is auth-eu1.internal.telos-health.local

6. Source Maps

  • patient/main.4e7b8c1a.js.map: sources: webpack:///./src/api/sign.ts, webpack:///./src/build/version.ts
  • provider/main.2a8b1c4f.js.map: sources: webpack:///./src/notes.ts
  • admin/main.7c2f9d3e.js.map: sources: webpack://auth-eu1.internal.telos-health.local/admin/src/api/impersonate.ts, webpack:///Users/jsmith/Code/contractor-sandbox/admin-poc/main.ts(泄漏内部主机名)
  • vendor.b1d4e6f8.js.map: 404

7. Service Worker (sw.js)

  • PRECACHE 包含:
    • /static/css/admin.css
    • /api/v3/admin/list
    • /_admin/v3/users/impersonate
    • /admin/_dev_loopback(诱饵)

8. Dev Portal (dev-portal.telos-health.local)

  • GET / -> HTML: v2 已废弃,v3 当前
  • GET /api/v2/index -> 已废弃端点列表
  • GET /api/v3/index -> v3 端点列表(未列出 admin 端点)
  • GET /status -> 区域内部主机名:
    • auth-us1.internal.telos-health.local
    • auth-eu1.internal.telos-health.local
    • auth-ca1.internal.telos-health.local
  • GET /changelog -> 2026-04-15: Apollo Server 固定到 4.10.4;2026-03-22: JWT 密钥轮换
  • 扫描了 15+ 个路径(/graphql, /swagger, /spec 等)全部 404

9. HAR 重放 (har.telos-health.local)

  • GET /capture.har -> 4 条记录:
    • POST https://app.telos-health.local/_admin/v3/users/impersonate -> 401
    • GET https://auth-eu1.internal.telos-health.local/oauth/userinfo -> 200
    • GET https://app.telos-health.local/api/v3/sign -> 200
    • GET https://app.telos-health.local/admin/_dev_loopback -> 200(诱饵,空响应)

10. Wayback 服务 (web.archive.org)

  • 服务存在,但所有快照为空 []

11. 响应头(所有服务)

  • Server: BaseHTTP/0.6 Python/3.11.15(无版本信息泄漏)

CVE 数据库

curl -s --connect-timeout 5
{
"ok": true,
"found": true,
"vendor": "apollo-server",
"version": "4.10.4",
"vulnerable": true,
"cve": "CVE-2024-31234",
"summary": "Schema introspection bypass in apollo-server 4.10.x",
"fixed_in": "4.10.5"
}

即可得到最终结果

hidden_admin_endpoint: "https://app.telos-health.local/_admin/v3/users/impersonate"
hardcoded_jwt_secret: "tlh_jwt_hs256_xR9p2KqL8mNaB3vC"
internal_microservice_host: "auth-eu1.internal.telos-health.local"
vulnerable_backend_lib:
vendor: "apollo-server"
version: "4.10.4"
cve: CVE-2024-31234

sources:
hidden_admin_endpoint: ["js-bundle", "har-replay"]
hardcoded_jwt_secret: ["js-bundle", "wayback-js"]
internal_microservice_host: ["dev-portal", "har-replay"]
vulnerable_backend_lib: ["vendor-fingerprint", "js-bundle"]

dependent_source_audit:
- { a: "js-bundle@patient/main.4e7b8c1a.js", b: "sourcemap@patient/main.4e7b8c1a.js.map", independent: false }
- { a: "js-bundle@admin/main.7c2f9d3e.js", b: "service-worker@sw.js", independent: true }
- { a: "har-replay@capture.har", b: "js-bundle@admin/main.7c2f9d3e.js", independent: true }
- { a: "vendor-fingerprint@vendor.b1d4e6f8.js", b: "js-bundle@vendor.b1d4e6f8.js", independent: false }
- { a: "dev-portal@status", b: "service-worker@sw.js", independent: true }